package com.admin.system.security.jwt;

import com.admin.monmon.util.AjaxResponse;
import com.admin.monmon.util.SecurityConstants;
import com.admin.system.security.service.UserDetailsServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.io.DecodingException;
import io.jsonwebtoken.security.SignatureException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;

/**
 * @author caixiaofeng
 * @version 1.0
 * @Description: <<>>
 * @company cxf
 * @create 2021-01-28 19:56
 */
@Component
public class JWTAuthenticationFilter extends OncePerRequestFilter {
    private static final Logger log = LoggerFactory.getLogger(JWTAuthenticationFilter.class);
    @Resource
    private UserDetailsServiceImpl userDetailsService;
    @Resource
    private JwtTokenUtils jwtTokenUtils;
    @Resource
    private ObjectMapper objectMapper;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        //判断是否为登录请求
        String requestUrl = request.getRequestURI();
        if (!SecurityConstants.AUTH_LOGIN_URL.equals(requestUrl)) {
            //从请求头中获得token
            String token = request.getHeader(SecurityConstants.TOKEN_HEADER);
            //判断token是否存在，且token是否过期
            if (!StringUtils.isEmpty(token)) {
                try {
                    //获得用户名
                    String username = jwtTokenUtils.getUsername(token);
                    //如果可以正确的从JWT中提取用户信息，并且该用户未被授权
                    if (!StringUtils.isEmpty(username) && ObjectUtils.isEmpty(SecurityContextHolder.getContext().getAuthentication())) {
                        //加载用户权限信息
                        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                        //给使用该JWT令牌的用户进行授权
                        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                        //添加认证，后面的usernamePasswordFilter就不会执行
                        SecurityContextHolder.getContext().setAuthentication(authentication);
                    }
                } catch (RuntimeException e) {
                    this.responseErrorHandler(e, response);
                    return;
                }
            }
        }
        chain.doFilter(request, response);
    }

    private void responseErrorHandler(RuntimeException e, HttpServletResponse response) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
        e.printStackTrace();
        //jwt过期异常
        if (e instanceof ExpiredJwtException) {
            log.warn("token过期");
            ExpiredJwtException expJwtException = (ExpiredJwtException) e;
            //token过期时间(毫秒)
            Integer exp = (Integer) expJwtException.getClaims().get("exp");
            //获得用户名
            String subUsername = (String) expJwtException.getClaims().get("sub");
            //算出间隔时间
            long Intervals = (System.currentTimeMillis() / 1000L) - exp;
            //在刷新token时间范围内，续费token
            if (SecurityConstants.TOKEN_REFRESH >= Intervals) {
                String newToken = jwtTokenUtils.generateToken(subUsername);
                response.setStatus(HttpServletResponse.SC_OK);
               // response.addHeader("refreshToken", newToken);
                PrintWriter writer = response.getWriter();
                HashMap<String, Object> map = new HashMap<>();
                map.put("refreshToken",newToken);
                writer .write(objectMapper.writeValueAsString(map));
                writer.flush();
                writer.close();
                return;
            }
            expJwtException.printStackTrace();
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("token过期");
        } else if (e instanceof UnsupportedJwtException) {
            log.warn("请求分析不支持的JWT");
            response.getWriter().write("请求分析不支持的Token");
        } else if (e instanceof MalformedJwtException) {
            log.warn("请求解析无效的JWT");
            response.getWriter().write("请求解析无效的Token");
        } else if (e instanceof SignatureException) {
            log.warn("请求解析签名无效的JWT");
            response.getWriter().write("请求解析签名无效的Token");
        } else if (e instanceof IllegalArgumentException) {
            log.warn("请求解析空的或空的JWT");
            response.getWriter().write("请求解析空的或空的Token");
        } else if (e instanceof DecodingException) {
            log.warn("JWT解析异常");
            response.getWriter().write("JWT解析异常");
        }

    }
}
